package com.tools.web.work.captcha;

import com.tools.common.object.Note;
import com.tools.common.object.json.JsonKit;
import com.tools.common.thread.TimePair;
import com.tools.common.thread.Timeunit;
import com.tools.middle.redis.client.JedisPlus;
import com.wf.captcha.base.Captcha;

import java.util.Map;
import java.util.Objects;

/**
 * 使用 JedisPlus 客户端操作单机 Redis 实现 CacheService
 * */
@Note("使用 JedisPlus 客户端操作单机 Redis 实现 CacheService")
public final class JedisPlusCaptchaService extends AbsCaptchaService implements CaptchaRedisLuaScript{

    @Note("操作 Redis 单机的客户端实例")
    private final JedisPlus jedisPlus;

    /* ********************************************************************************************
     *
     *          构造器
     *
     * *********************************************************************************************
     * */

    public JedisPlusCaptchaService(JedisPlus jedisPlus) {
        this.jedisPlus = Objects.requireNonNull(jedisPlus);
    }

    /* ********************************************************************************************
     *
     *          工具方法
     *
     * *********************************************************************************************
     * */

    public JedisPlus getJedisPlus() {
        return jedisPlus;
    }

    @Override
    public int checkEqualsCaptcha(String key, String sourceCode, boolean ignoreCase) {
        try {
            Integer result = (Integer) this.jedisPlus.eval(CHECK_EQUALS, 1, key, sourceCode, ignoreCase);
            return result != null ? result : 0;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public int checkEqualsCaptcha(String key, String sourceCode) {
        return this.checkEqualsCaptcha(key, sourceCode, true);
    }

    @Override
    public int checkSlideCaptcha(String key, SlideCaptcha source) {
        try {
            Integer result = (Integer) this.jedisPlus.eval(CHECK_SLIDE, 1, key,
                    source.getBlockX(), source.getBlockY());
            return result != null ? result : 0;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public int checkClickCaptcha(String key, ClickCaptcha source) {
        try {
            String charsJson = JsonKit.toJSON(source.getChars());
            Integer result = (Integer) this.jedisPlus.eval(CHECK_CLICK, 1, key, charsJson);
            return result != null ? result : 0;
        } finally {
            this.jedisPlus.close();
        }
    }


    @Override
    public void setEqualsCaptcha(String key, CaptchaResult captchaResult, long expiration, Timeunit timeunit) {
        try {
            long expirationSecond = Timeunit.toSecond(expiration, timeunit);
            this.jedisPlus.eval(SET_EQ_AND_CLICK_CAPTCHA, 1, key,
                    expirationSecond, captchaResult.asTextIfIs(),
                    captchaResult.getAllow(), captchaResult.getIncorrect());
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public void setEqualsCaptcha(String key, CaptchaResult captchaResult, TimePair expiration) {
        this.setEqualsCaptcha(key, captchaResult, expiration.getSourceTime(), expiration.getSourceTimeunit());
    }

    @Override
    public void setSlideCaptcha(String key, CaptchaResult captchaResult, long expiration, Timeunit timeunit) {
        try {
            long expirationSecond = Timeunit.toSecond(expiration, timeunit);
            SlideCaptcha slide = (SlideCaptcha) captchaResult.getCaptcha();
            this.jedisPlus.eval(SET_SLIDE_CAPTCHA, 1, key,
                    expirationSecond, slide.getBlockX(), slide.getBlockY(),
                    slide.getFaultTolerant(),
                    captchaResult.getAllow(), captchaResult.getIncorrect());
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public void setSlideCaptcha(String key, CaptchaResult captchaResult, TimePair expiration) {
        this.setSlideCaptcha(key, captchaResult, expiration.getSourceTime(), expiration.getSourceTimeunit());
    }

    @Override
    public void setClickSelectCaptcha(String key, CaptchaResult captchaResult, long expiration, Timeunit timeunit) {
        try {
            ClickCaptcha clickCaptcha = (ClickCaptcha) captchaResult.getCaptcha();
            String captcha = JsonKit.toJSON(clickCaptcha.getChars());
            long expirationSecond = Timeunit.toSecond(expiration, timeunit);
            this.jedisPlus.eval(SET_EQ_AND_CLICK_CAPTCHA, 1, key,
                    expirationSecond, captcha,
                    captchaResult.getAllow(), captchaResult.getIncorrect());
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public void setClickSelectCaptcha(String key, CaptchaResult captchaResult, TimePair expiration) {
        this.setClickSelectCaptcha(key, captchaResult, expiration.getSourceTime(), expiration.getSourceTimeunit());
    }

    @Override
    public CaptchaResult getEqualsCaptcha(String key) {
        try {
            Map<String, String> map = this.jedisPlus.jedis().hgetAll(key);
            String captcha = map.get("captcha");
            int allow = Integer.parseInt(map.get("allow"));
            int incorrect = Integer.parseInt(map.get("incorrect"));
            CaptchaResult captchaResult = new CaptchaResult(captcha, allow);
            captchaResult.setIncorrect(incorrect);
            return captchaResult;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public CaptchaResult getSlideCaptcha(String key) {
        try {
            Map<String, String> map = this.jedisPlus.jedis().hgetAll(key);
            int blockX = Integer.parseInt(map.get("blockX"));
            int blockY = Integer.parseInt(map.get("blockY"));
            int faultTolerant = Integer.parseInt(map.get("faultTolerant"));
            int allow = Integer.parseInt(map.get("allow"));
            int incorrect = Integer.parseInt(map.get("incorrect"));
            SlideCaptcha slideCaptcha = new SlideCaptcha(blockX, blockY, faultTolerant);
            CaptchaResult captchaResult = new CaptchaResult(slideCaptcha, allow);
            captchaResult.setIncorrect(incorrect);
            return captchaResult;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public CaptchaResult getClickSelectCaptcha(String key) {
        try {
            Map<String, String> map = this.jedisPlus.jedis().hgetAll(key);
            String captcha = map.get("captcha");
            int allow = Integer.parseInt(map.get("allow"));
            int incorrect = Integer.parseInt(map.get("incorrect"));
            ClickCaptcha clickCaptcha = JsonKit.toEntity(captcha, ClickCaptcha.class);
            CaptchaResult captchaResult = new CaptchaResult(clickCaptcha, allow);
            captchaResult.setIncorrect(incorrect);
            return captchaResult;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public void removeCaptcha(String key) {
        try {
            this.jedisPlus.jedis().del(key);
        } finally {
           this.jedisPlus.close();
        }
    }
}
